
using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using SkiaSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;


using System.Threading.Tasks;
using System.Xml.Linq;
using LightCAD.MathLib;
using Avalonia.Media.TextFormatting.Unicode;
using static LightCAD.Three.Raycaster;
using System.ComponentModel;
using LightCAD.Three;


namespace LightCAD.Drawing.Actions
{
    public class CircleAction : Curve2dAction
    {
        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;

        static CircleAction()
        {
            CommandName = "CIRCLE";
            CreateMethods = new LcCreateMethod[6];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "CR",
                Description = "圆心半径画圆",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="SpecifyCenter", Options="指定圆的圆心或[三点(3P) 二点(2P) 切点,切点,半径(T)]:" },
                    new LcCreateStep{ Name="SpecifyRadius", Options="指定圆的半径或[直径(D)]:" },
                    new LcCreateStep{ Name="SpecifyDiameter",Options="指定圆的直径:"},
                }
            };
            CreateMethods[1] = new LcCreateMethod()
            {
                Name = "3P",
                Description = "三点画圆",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="SpecifyPoint1", Options="指定圆直径的第一个端点:" },
                    new LcCreateStep{ Name="SpecifyPoint2", Options="指定圆直径的第二个端点:" },
                    new LcCreateStep{ Name="SpecifyPoint3", Options="指定圆直径的第三个端点:" },
                }
            };
            CreateMethods[2] = new LcCreateMethod()
            {
                Name = "2P",
                Description = "二点画圆",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="SpecifyPoint1", Options="指定圆直径的第一个端点:" },
                    new LcCreateStep{ Name="SpecifyPoint2", Options="指定圆直径的第二个端点:" },
                }
            };
            CreateMethods[3] = new LcCreateMethod()
            {
                Name = "CD",
                Description = "圆心直径画圆",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="SpecifyCenter", Options="指定圆的圆心或[三点(3P) 两点(2P) 切点、切点、半径(T)]:" },
                    new LcCreateStep{ Name="SpecifyDiameter", Options="指定圆的半径或[直径(D)]:_d 指定圆的直径:" },
                }
            };
            CreateMethods[4] = new LcCreateMethod()
            {
                Name = "T",
                Description = "相切相切半径画圆",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="SpecifyPoint1", Options="指定对象与圆的第一个切点:" },
                    new LcCreateStep{ Name="SpecifyPoint2", Options="指定对象与圆的第二个切点:" },
                    new LcCreateStep{ Name="SpecifyRadius", Options="指定圆的半径:" },
                    new LcCreateStep{ Name="SpecifyPoint3", Options="指定圆的半径: 指定第二点:" },
                    new LcCreateStep{ Name="SpecifyPoint4", Options="两条直线平行，指定一点确定圆心:" },
                }
            };
            CreateMethods[5] = new LcCreateMethod()
            {
                Name = "TTT",
                Description = "相切相切相切画圆",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep{ Name="SpecifyPoint1", Options="指定圆的圆心或[三点(3P) 两点(2P) 切点、切点、半径(T)]: _3p指定圆上的第一个点:_tan 到" },
                    new LcCreateStep{ Name="SpecifyPoint2", Options="指定圆上的第二个点:_tan 到" },
                    new LcCreateStep{ Name="SpecifyPoint3", Options="指定圆上的第三个点:_tan 到" },
                }
            };
        }

        internal static void Initilize()
        {
            ElementActions.Circle = new CircleAction();
            LcDocument.ElementActions.Add(BuiltinElementType.Circle, ElementActions.Circle);
        }

        private PointInputer inputer { get; set; }

        private Vector2 cr_center;
        private Vector2 cr_point;
        private Vector2 _point1;
        private Vector2 _point2;
        private Vector2 _point3;
        private Vector2 _point4;//T的第四个点
        private Vector2 _point5;
        private Vector2 _tangent1;
        private Vector2 _tangent2;
        private Vector2? cd_center;
        private Vector2? cd_point;
        private string _methodName;
        private string _methodArg;
        List<LcLine> li = new List<LcLine>();
        List<LcLine> li1 = new List<LcLine>();
        private bool result;
        private double radius;
        private Vector2? center;
        public CircleAction() { }
        public CircleAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCenter.WriteInfo("命令：" + CommandName);
        }
        private LcCreateMethod GetMethod(string method)
        {
            if (method == null)
                return SetCurMethod(CreateMethods, 0);

            int getted = CreateMethods.ToList().FindIndex(m => m.Name == method);
            if (getted == -1)
                return SetCurMethod(CreateMethods, 0);
            else
                return SetCurMethod(CreateMethods, getted);
        }
        public async void ExecCreate(string[] args = null)
        {
            var method = "CR";
            if (args != null && args.Length > 0)
            {
                method = args[0];
            }
            var curMethod = this.GetMethod(method);
            _methodName = curMethod.Name;
            this.inputer = new PointInputer(this.docEditor);
            this.StartCreating();
            if (curMethod.Name == "CR") goto Method_CR_Step0;
            if (curMethod.Name == "2P") goto Method_2P_Step0;
            if (curMethod.Name == "3P") goto Method_3P_Step0;
            if (curMethod.Name == "CD") goto Method_CD_Step0;
            if (curMethod.Name == "T") goto Method_T_Step0;
            if (curMethod.Name == "TTT") goto Method_TTT_Step0;

            return;
        #region Method_CR_Step0
        Method_CR_Step0:
            var cr_step0 = SetCurStep(curMethod, 0);
            _methodName = curMethod.Name;
            var cr_result0 = await inputer.Execute(cr_step0.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (cr_result0.ValueX == null)
            {
                if (cr_result0.Option != null && cr_result0.Option.ToUpper() == "2P")
                {
                    goto Method_2P_Step0;
                }
                else if (cr_result0.Option != null && cr_result0.Option.ToUpper() == "3P")
                    goto Method_3P_Step0;
                else if (cr_result0.Option != null && cr_result0.Option.ToUpper() == "T")
                {
                    goto Method_T_Step0;
                }
                else
                {
                    goto Method_CR_Step0;
                }
            }
            this.cr_center = (Vector2)cr_result0.ValueX;


        Method_CR_Step1:
            var cr_step1 = SetCurStep(curMethod, 1);
            var cr_result1 = await inputer.Execute(cr_step1.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (cr_result1.ValueX == null)
            {
                if (cr_result1.Option == "D")
                {
                    this._methodArg = "D";
                    goto Method_CD_Step0;
                }
            }
            this.cr_point = (Vector2)cr_result1.ValueX;
            goto End;
        #endregion

        #region Method_2P_Step0
        Method_2P_Step0:
            curMethod = this.SetCurMethod(CreateMethods, 2);
            _methodName = curMethod.Name;
            var _2p_step0 = SetCurStep(curMethod, 0);
            var _2p_result0 = await inputer.Execute(_2p_step0.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (_2p_result0.ValueX == null)
            {
                goto Method_2P_Step0;
            }
            this._point1 = (Vector2)_2p_result0.ValueX;

        Method_2P_Step1:
            var _2p_step1 = SetCurStep(curMethod, 1);
            var _2p_result1 = await inputer.Execute(_2p_step1.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (_2p_result1.ValueX == null)
            {
                goto Method_2P_Step1;
            }
            this._point2 = (Vector2)_2p_result1.ValueX;
            goto End;
        #endregion

        #region Method_3P_Step0
        Method_3P_Step0:
            curMethod = this.SetCurMethod(CreateMethods, 1);
            _methodName = curMethod.Name;
            var _3p_step0 = SetCurStep(curMethod, 0);
            var _3p_result0 = await inputer.Execute(_3p_step0.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (_3p_result0.ValueX == null)
            {
                goto Method_3P_Step0;
            }
            this._point1 = (Vector2)_3p_result0.ValueX;
        Method_3P_Step1:
            var _3p_step1 = SetCurStep(curMethod, 1);
            var _3p_result1 = await inputer.Execute(_3p_step1.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (_3p_result1.ValueX == null)
            {
                goto Method_3P_Step1;
            }
            this._point2 = (Vector2)_3p_result1.ValueX;
        Method_3P_Step2:
            var _3p_step2 = SetCurStep(curMethod, 2);
            var _3p_result2 = await inputer.Execute(_3p_step2.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (_3p_result2.ValueX == null)
            {
                goto Method_3P_Step2;
            }
            this._point3 = (Vector2)_3p_result2.ValueX;
            goto End;
        #endregion

        #region Method_CD_Step0
        Method_CD_Step0:
            curMethod = this.SetCurMethod(CreateMethods, 3);
            _methodName = curMethod.Name;
            var cd_step0 = SetCurStep(curMethod, 0);
            var cd_result0 = await inputer.Execute(cd_step0.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (cd_result0.ValueX == null)
            {
                if (cd_result0.Option != null && cd_result0.Option.ToUpper() == "2P")
                {
                    goto Method_2P_Step0;
                }
                else if (cd_result0.Option != null && cd_result0.Option.ToUpper() == "3P")
                    goto Method_3P_Step0;
                else if (cd_result0.Option != null && cd_result0.Option.ToUpper() == "T")
                {
                    goto Method_T_Step0;
                }
                else
                {
                    goto Method_CD_Step0;
                }
            }
            this.cd_center = (Vector2)cd_result0.ValueX;

        Method_CD_Step1:
            var cd_step1 = SetCurStep(curMethod, 1);
            var cd_result1 = await inputer.Execute(cd_step1.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (cd_result1.ValueX == null)
            {
                goto Method_CD_Step1;
            }
            this.cd_point = (Vector2)cd_result1.ValueX;
            goto End;
        #endregion

        #region Method_T_Step0
        Method_T_Step0:
            curMethod = this.SetCurMethod(CreateMethods, 4);
            _methodName = curMethod.Name;
            var t_step0 = SetCurStep(curMethod, 0);
            var t_result0 = await inputer.Execute(t_step0.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (t_result0.ValueX == null)
            {
                goto Method_T_Step0;
            }
            else
            {
                if (pointInLine((Vector2)t_result0.ValueX) != null)
                {
                    li1.Add(pointInLine((Vector2)t_result0.ValueX));
                }
                else
                {
                    this.commandCenter.WriteInfo("选取的点无效");
                    goto Method_T_Step0;
                }
            }
            this._point1 = (Vector2)t_result0.ValueX;

        Method_T_Step1:
            var t_step1 = SetCurStep(curMethod, 1);
            var t_result1 = await inputer.Execute(t_step1.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (t_result1.ValueX == null)
            {
                goto Method_T_Step1;
            }
            else
            {
                if (pointInLine((Vector2)t_result1.ValueX) != null)
                {
                    if (pointInLine((Vector2)t_result1.ValueX) != li1[0])
                    {
                        li1.Add(pointInLine((Vector2)t_result1.ValueX));
                    }
                    else
                    {
                        this.commandCenter.WriteInfo("选取的点在同一直线上");
                        goto Method_T_Step1;
                    }
                }
                else
                {
                    this.commandCenter.WriteInfo("选取的点无效");
                    goto Method_T_Step1;
                }
            }
            this._point2 = (Vector2)t_result1.ValueX;
            result = TwoLineIsParallel(li1[0], li1[1]);
            //判断两条线是否平行
            if (result == true)
            {
                goto Method_T_Step4;
            }
            else
            {
                goto Method_T_Step2;
            }

        Method_T_Step2:
            var t_step2 = SetCurStep(curMethod, 2);
            var t_result2 = await inputer.Execute(t_step2.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }

            if (t_result2.ValueX == null)
            {
                if (t_result2.Option.GetType() == typeof(string))
                {
                    double i = 0;
                    if (double.TryParse(t_result2.Option, out i) == true)
                    {
                        radius = i;
                    }
                    else
                    {
                        goto Method_T_Step2;
                    }
                }
            }
            this._point3 = (Vector2)t_result2.ValueX;
            if (radius != 0.0)
            {
                center = GetCircleByT();
                goto End;
            }

        Method_T_Step3:
            var t_step3 = SetCurStep(curMethod, 3);
            var t_result3 = await inputer.Execute(t_step3.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (t_result3.ValueX == null)
            {
                goto Method_T_Step3;
            }
            this._point4 = (Vector2)t_result3.ValueX;
            radius = GetDistanceByTwoPoints(_point3, _point4) / 2;
            center = GetCircleByT();

            goto End;


        Method_T_Step4:
            var t_step4 = SetCurStep(curMethod, 4);
            var t_result4 = await inputer.Execute(t_step4.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (t_result4.ValueX == null)
            {
                goto Method_T_Step4;
            }
            radius = GetDistanceByTwoParallelLine(li1[0], li1[1]);
            this._point5 = (Vector2)t_result4.ValueX;
            center = GetCircleByT1(_point5);
            goto End;
        #endregion

        #region Method_TTT_Step0
        Method_TTT_Step0:
            curMethod = this.SetCurMethod(CreateMethods, 5);
            _methodName = curMethod.Name;
            var ttt_step0 = SetCurStep(curMethod, 0);
            var ttt_result0 = await inputer.Execute(ttt_step0.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }

            if (ttt_result0.ValueX == null)
            {
                if (ttt_result0.Option != null && ttt_result0.Option.ToUpper() == "2P")
                    goto Method_2P_Step0;
                else if (ttt_result0.Option != null && ttt_result0.Option.ToUpper() == "3P")
                    goto Method_3P_Step0;
                else if (ttt_result0.Option != null && ttt_result0.Option.ToUpper() == "TTR")
                    goto Method_T_Step0;
                else
                {
                    goto Method_TTT_Step0;
                }
            }
            else
            {
                if (pointInLine((Vector2)ttt_result0.ValueX) != null)
                {
                    li.Add(pointInLine((Vector2)ttt_result0.ValueX));
                }
                else
                {
                    this.commandCenter.WriteInfo("选取的点无效");
                    goto Method_TTT_Step0;
                }
            }
            this._point1 = (Vector2)ttt_result0.ValueX;

        Method_TTT_Step1:
            var ttt_step1 = SetCurStep(curMethod, 1);
            var ttt_result1 = await inputer.Execute(ttt_step1.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (ttt_result1.ValueX == null)
            {
                goto Method_TTT_Step1;
            }
            else
            {
                if (pointInLine((Vector2)ttt_result1.ValueX) != null)
                {
                    if (pointInLine((Vector2)ttt_result1.ValueX) != li[0])
                    {
                        li.Add(pointInLine((Vector2)ttt_result1.ValueX));
                    }
                    else
                    {
                        this.commandCenter.WriteInfo("选取的点在同一直线上");
                        goto Method_TTT_Step1;
                    }
                }
                else
                {
                    this.commandCenter.WriteInfo("选取的点无效");
                    goto Method_TTT_Step1;
                }
            }
            this._point2 = (Vector2)ttt_result1.ValueX;

        Method_TTT_Step2:
            var ttt_step2 = SetCurStep(curMethod, 2);
            var ttt_result2 = await inputer.Execute(ttt_step2.Options);
            if (inputer.isCancelled) { this.Cancel(); return; }
            if (ttt_result2.ValueX == null)
            {
                goto Method_TTT_Step2;
            }
            else
            {
                if (pointInLine((Vector2)ttt_result2.ValueX) != null)
                {
                    if ((pointInLine((Vector2)ttt_result2.ValueX) != li[0]) && (pointInLine((Vector2)ttt_result2.ValueX) != li[1]))
                    {
                        li.Add(pointInLine((Vector2)ttt_result2.ValueX));
                    }
                    else
                    {
                        this.commandCenter.WriteInfo("选取的点在同一直线上");
                        goto Method_TTT_Step2;
                    }
                }
                else
                {
                    this.commandCenter.WriteInfo("选取的点无效");
                    goto Method_TTT_Step2;
                }
            }
            this._point3 = (Vector2)ttt_result2.ValueX;
            goto End;
        #endregion
        End:
            CreateCircleElement();
            this.inputer = null;
            this.EndCreating();
        }
        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
        }
        private void CreateCircleElement()
        {
            if (_methodName == "CR")
            {
                if (_methodArg == "D")
                    this.vportRt.ActiveElementSet.AddCircle(cr_center, Vector2.Distance(cr_point, cr_center) / 2);
                else
                    this.vportRt.ActiveElementSet.AddCircle(cr_center, Vector2.Distance(cr_point, cr_center));
            }
            else if (_methodName == "2P")
            {
                var c = (_point1 + _point2) / 2;
                var r = Vector2.Distance(_point1, _point2) / 2;
                this.vportRt.ActiveElementSet.AddCircle(c, r);
            }
            else if (_methodName == "3P")
            {
                var valid = getCircleBy3P(_point1, _point2, _point3, out var c, out var r);
                if (valid)
                    this.vportRt.ActiveElementSet.AddCircle(c, r);
                else
                    Debug.Assert(valid, "三点共线无法创建圆！！");
            }
            else if (_methodName == "CD")
            {
                this.vportRt.ActiveElementSet.AddCircle(cd_center, Vector2.Distance(cd_center, cd_point) / 2);
            }
            else if (_methodName == "T")
            {

                this.vportRt.ActiveElementSet.AddCircle(center, radius);
            }
            else if (_methodName == "TTT")
            {
                var valid = GetCircleByTTT(_point1, _point2, _point3, out var c, out var r);
                if (valid)
                    this.vportRt.ActiveElementSet.AddCircle(c, r);
            }
        }
        private bool getCircleBy3P(Vector2 a, Vector2 b, Vector2 c, out Vector2? center, out double radius)
        {
            double A, B, C, D;
            double x1 = a.X, x2 = b.X, x3 = c.X;
            double y1 = a.Y, y2 = b.Y, y3 = c.Y;
            //已知三个点确定圆的半径和圆心 
            double x1x1 = x1 * x1;
            double y1y1 = y1 * y1;
            double x2x2 = x2 * x2;
            double y2y2 = y2 * y2;
            double x3x3 = x3 * x3;
            double y3y3 = y3 * y3;

            double x2y3 = x2 * y3;
            double x3y2 = x3 * y2;

            double x2_x3 = x2 - x3;
            double y2_y3 = y2 - y3;

            double x1x1py1y1 = x1x1 + y1y1;
            double x2x2py2y2 = x2x2 + y2y2;
            double x3x3py3y3 = x3x3 + y3y3;

            A = x1 * y2_y3 - y1 * x2_x3 + x2y3 - x3y2;
            if (A == 0)
            {
                center = null;
                radius = 0;
                return false;
            }
            B = x1x1py1y1 * (-y2_y3) + x2x2py2y2 * (y1 - y3) + x3x3py3y3 * (y2 - y1);
            C = x1x1py1y1 * x2_x3 + x2x2py2y2 * (x3 - x1) + x3x3py3y3 * (x1 - x2);
            D = x1x1py1y1 * (x3y2 - x2y3) + x2x2py2y2 * (x1 * y3 - x3 * y1) + x3x3py3y3 * (x2 * y1 - x1 * y2);

            var x = -B / (2 * A);
            var y = -C / (2 * A);
            radius = Math.Sqrt((B * B + C * C - 4 * A * D) / (4 * A * A));
            center = new Vector2(x, y);
            return true;
        }
        private LcLine pointInLine(Vector2 a)
        {
            var lis = this.docRt.Document.ModelSpace.Elements.Where((ele) => ele.Type == BuiltinElementType.Line).ToList();
            foreach (var li in lis)
            {
                LcLine line1 = li as LcLine;
                if (Line2d.PointInLine(line1.Start, line1.End, a))
                {
                    return line1;
                }
            }
            return null;
        }
        private bool TwoLineIsParallel(LcLine linea, LcLine lineb)
        {
            double x1 = linea.Start.X, x2 = linea.End.X, x3 = lineb.Start.X, x4 = lineb.End.X;
            double y1 = linea.Start.Y, y2 = linea.End.Y, y3 = lineb.Start.Y, y4 = lineb.End.Y;
            double m1, m2;
            if (x1 == x2 && x3 == x4)
            {
                return true;
            }
            else if (y1 == y2 && y3 == y4)
            {
                return true;
            }
            else 
            {
                 m1 = (linea.End.Y - linea.Start.Y) / (linea.End.X - linea.Start.X);
                 m2 = (lineb.End.Y - lineb.Start.Y) / (lineb.End.X - lineb.Start.X);           
                if(m1 == m2)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            } 
        }
        private double GetDistanceByTwoParallelLine(LcLine line0, LcLine line1)
        {
            Line2d linea = new(line0.Start, line0.End); Line2d lineb = new(line1.Start, line1.End);
            double x1 = linea.Start.X, x2 = linea.End.X, x3 = lineb.Start.X, x4 = lineb.End.X;
            double y1 = linea.Start.Y, y2 = linea.End.Y, y3 = lineb.Start.Y, y4 = lineb.End.Y;
            double m1 = (linea.End.Y - linea.Start.Y) / (linea.End.X - linea.Start.X);
            double m2 = (lineb.End.Y - lineb.Start.Y) / (lineb.End.X - lineb.Start.X);
            double b1 = 1.0, b2 = 1.0;
            double radius;
            double c1 = -m1 * x1 + b1 * y1, c2 = -m2 * x3 + b2 * y3;
            if (x1 == x2 && x3 == x4)
            {
                radius = Math.Abs(x3 - x1) / 2;
            }
            else if (y1 == y2 && y3 == y4)
            {
                radius = Math.Abs(y1 - y3) / 2;
            }
            else
            {
                radius = (Math.Abs(c1 - c2) / Math.Sqrt(Math.Pow(m1, 2) + Math.Pow(b1, 2))) / 2;
            }
            return radius;
        }

        private Vector2? GetCircleByT()
        {
            #region 原写法
            //var lis = this.docRt.Document.ModelSpace.Elements.Where((ele) => ele.Type == BuiltinElementType.Line).ToList();
            //Line2d linea = new Line2d();
            //Line2d lineb= new Line2d();
            //foreach (var li in lis)
            //{
            //    LcLine line1 = li as LcLine;
            //    if (Line2d.PointInLine(line1.Start, line1.End, a))
            //    {
            //        linea = new Line2d(line1.Start,line1.End);
            //    }
            //    if (Line2d.PointInLine(line1.Start, line1.End, b))
            //    {
            //        lineb = new Line2d(line1.Start, line1.End);
            //    }
            //}
            #endregion
            LcLine line0 = li1[0]; LcLine line1 = li1[1];
            Line2d linea = new(line0.Start, line0.End); Line2d lineb = new(line1.Start, line1.End);

            double x1 = linea.Start.X, x2 = linea.End.X, x3 = lineb.Start.X, x4 = lineb.End.X;
            double y1 = linea.Start.Y, y2 = linea.End.Y, y3 = lineb.Start.Y, y4 = lineb.End.Y;
            double m1 = (linea.End.Y - linea.Start.Y) / (linea.End.X - linea.Start.X);
            double m2 = (lineb.End.Y - lineb.Start.Y) / (lineb.End.X - lineb.Start.X);
            double b1 = 1.0, b2 = 1.0;
            double c1 = -m1 * x1 + b1 * y1, c2 = -m2 * x3 + b2 * y3;

            //求两条切线延长线的交点
            double xp = (c2 - c1) / (m1 - m2);
            double yp = m1 * xp + c1;

            //统一两条切线的方向 朝外
            double aStart = GetDistanceByTwoPoints(new(xp, yp), linea.Start);
            double aEnd = GetDistanceByTwoPoints(new(xp, yp), linea.End);
            if (aStart > aEnd)
            {
                linea = new Line2d(linea.End, linea.Start);
            }
            else
            {
                linea = linea;
            }
            double bStart = GetDistanceByTwoPoints(new(xp, yp), lineb.Start);
            double bEnd = GetDistanceByTwoPoints(new(xp, yp), lineb.End);
            if (bStart > bEnd)
            {
                lineb = new Line2d(lineb.End, lineb.Start);
            }
            else
            {
                lineb = lineb;
            }

            //求解两条延长线的夹角
            double angleDeg = GetDegreesByTwoLine(linea.Start, linea.End, lineb.Start, lineb.End);
            double angle1 = angleDeg / 2;

            //求解角平分线的长度
            double lengthl1 = radius / Math.Sin(angle1 * Math.PI / 180);

            ////统一过交点的参考线与两条切线的方向
            Line2d lineP = new Line2d();
            lineP.Start = new(xp, yp);
            lineP.End = new(xp + 100, yp);

            //求交点与X轴的平行线 与 每条切线的夹角       
            double angleDeg1 = GetDegreesByTwoLine(linea.Start, linea.End, lineP.Start, lineP.End);
            double angleDeg2 = GetDegreesByTwoLine(lineb.Start, lineb.End, lineP.Start, lineP.End);
            if (IsTopInLine(linea.Start, linea.End, lineP.End) < 0)//左侧需减
            {
                angleDeg1 = 360 - angleDeg1;
            }
            if (IsTopInLine(lineb.Start, lineb.End, lineP.End) < 0)
            {

                angleDeg2 = 360 - angleDeg2;
            }
            double lineMidDegree = 0;
            //double comparey = 0;
            if (angleDeg1 < angleDeg2)
            {
                if ((angleDeg2 - angleDeg1) > 180)
                {
                    lineMidDegree = angleDeg2 + angle1;
                    if (lineMidDegree > 360)
                    {
                        lineMidDegree = lineMidDegree - 360;
                    }
                    //comparey = lineb.End.Y;
                }
                else
                {
                    lineMidDegree = angleDeg1 + angle1;
                    //comparey = linea.End.Y;
                }
            }
            else
            {
                if ((angleDeg1 - angleDeg2) > 180)
                {
                    lineMidDegree = angleDeg1 + angle1;
                    if (lineMidDegree > 360)
                    {
                        lineMidDegree = lineMidDegree - 360;
                    }
                    //comparey = lineb.End.Y;
                }
                else
                {
                    lineMidDegree = angleDeg2 + angle1;
                    //comparey = linea.End.Y;
                }
            }
            double lineMidk = Math.Tan(lineMidDegree * Math.PI / 180);
            double lineMidb = yp - lineMidk * xp;
            double yc = 0.0;
            //判断中心线在哪个象限
            if (0 <= lineMidDegree && lineMidDegree <= 90)
            {

                yc = yp + lengthl1 * Math.Sin(lineMidDegree * Math.PI / 180);
            }
            else if (90 < lineMidDegree && lineMidDegree <= 180)
            {
                lineMidDegree = 180 - lineMidDegree;
                yc = yp + lengthl1 * Math.Sin(lineMidDegree * Math.PI / 180);
            }
            else if (180 < lineMidDegree && lineMidDegree <= 270)
            {
                lineMidDegree = lineMidDegree - 180;
                yc = yp - lengthl1 * Math.Sin(lineMidDegree * Math.PI / 180);
            }
            else if (270 < lineMidDegree && lineMidDegree <= 360)
            {
                lineMidDegree = 360 - lineMidDegree;
                yc = yp - lengthl1 * Math.Sin(lineMidDegree * Math.PI / 180);
            }
            //if(yp > comparey)
            //{
            //     yc = yp - lengthl1 * Math.Sin(lineMidDegree*Math.PI/180);
            //}
            //else
            //{
            //    yc = yp + lengthl1 * Math.Sin(lineMidDegree * Math.PI / 180);
            //}
            double xc = (yc - lineMidb) / lineMidk;
            Vector2? center = new(xc, yc);
            return center;
        }
        //两个平行线求圆心
        private Vector2? GetCircleByT1(Vector2 a)
        {
            LcLine line0 = li1[0]; LcLine line1 = li1[1];
            Line2d linea = new(line0.Start, line0.End); Line2d lineb = new(line1.Start, line1.End);
            double x1 = linea.Start.X, x2 = linea.End.X, x3 = lineb.Start.X, x4 = lineb.End.X;
            double y1 = linea.Start.Y, y2 = linea.End.Y, y3 = lineb.Start.Y, y4 = lineb.End.Y;
            double m1 = (linea.End.Y - linea.Start.Y) / (linea.End.X - linea.Start.X);
            double m2 = (lineb.End.Y - lineb.Start.Y) / (lineb.End.X - lineb.Start.X);
            double b1 = 1.0, b2 = 1.0;
            double c1 = -m1 * x1 + b1 * y1, c2 = -m2 * x3 + b2 * y3;
            double k, b, xc, yc;
            double ax = a.X, ay = a.Y;
            if (x1 == x2 && x3 == x4)
            {
                //m1 = 1; m2 = 1;
                //b1 = 0;b2 = 0;
                //c1 = -x1;c2 = -x3;
                yc = ay;
                if (x3 > x1)
                {
                    xc = (x3 - x1) / 2 + x1;
                }
                else
                {
                    xc = (x1 - x3) / 2 + x3;
                }
            }
            else if (y1 == y2 && y3 == y4)
            {
                xc = ax;
                if (y3 > y1)
                {
                    yc = (y3 - y1) / 2 + y1;
                }
                else
                {
                    yc = (y1 - y3) / 2 + y3;
                }
            }
            else
            {
                //  求出中心平行线的参数k和b
                k = m1;
                if (c1 > c2)
                {
                    b = ((c1 - c2) / 2) + c2;
                }
                else
                {
                    b = ((c2 - c1) / 2) + c1;
                }
                //求与两条平行线的垂点的X坐标              
                double verticalm = -1 / m1;
                double verticalc = ay - verticalm * ax;
                double intersectionPointa = (verticalc - c1) / (m1 - verticalm);
                double intersectionPointb = (verticalc - c2) / (m2 - verticalm);
                //求圆心的x坐标
                xc = (intersectionPointa + intersectionPointb) / 2;
                yc = k * xc + b;
            }
            Vector2? center = new(xc, yc);
            return center;
        }
        public double GetDegreesByTwoLine(Vector2 line1start, Vector2 line1End, Vector2 line2start, Vector2 line2End)
        {
            double x1 = line1start.X;
            double y1 = line1start.Y;
            double x2 = line1End.X;
            double y2 = line1End.Y;
            double x3 = line2start.X;
            double y3 = line2start.Y;
            double x4 = line2End.X;
            double y4 = line2End.Y;

            // 计算线段的向量表示
            double v1x = x2 - x1;
            double v1y = y2 - y1;
            double v2x = x4 - x3;
            double v2y = y4 - y3;

            // 计算向量的内积
            double dotProduct = v1x * v2x + v1y * v2y;


            // 计算向量的长度
            double magnitudeV1 = Math.Sqrt(v1x * v1x + v1y * v1y);
            double magnitudeV2 = Math.Sqrt(v2x * v2x + v2y * v2y);

            // 计算夹角余弦值
            double cosine = dotProduct / (magnitudeV1 * magnitudeV2);

            // 将夹角余弦值转换为角度
            double angleRadians = Math.Acos(cosine);
            double angleDegrees = angleRadians * 180 / Math.PI;
            return angleDegrees;
        }
        public double GetDistanceByTwoPoints(Vector2 linepoint1, Vector2 linepoint2)
        {
            double x1 = linepoint1.X, x2 = linepoint2.X;
            double y1 = linepoint1.Y, y2 = linepoint2.Y;
            double distance = Math.Sqrt(Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2));
            return distance;
        }
        public int IsTopInLine(Vector2 line1start, Vector2 line1End, Vector2 point)
        {
            Vector2 S;
            Vector2 E;
            
            S = line1End;
            E = line1start;

            double Tmp = (S.Y - E.Y) * point.X + (E.X - S.X) * point.Y + S.X * E.Y - E.X * S.Y;
            if (Tmp == 0)
            {
                return 0;
            }
            if (Tmp > 0)
            {
                return 1;
            }
            else
            { return -1; }
            //Tmp < 0 在左侧

            //Tmp = 0 在线上

            //Tmp >0 在右侧
        }
        private bool GetCircleByTTT(Vector2 a, Vector2 b, Vector2 c, out Vector2? center, out double radius)
        {
            LcLine line0 = li[0]; LcLine line1 = li[1]; LcLine line2 = li[2];
            Line2d linea = new(line0.Start, line0.End); Line2d lineb = new(line1.Start, line1.End); Line2d linec = new(line2.Start, line2.End);
            //求圆心
            double b1 = GetParameterOfMidLine(linea, lineb, out double k1);
            double b2 = GetParameterOfMidLine(lineb, linec, out double k2);
            double xc = (b2 - b1) / (k1 - k2);
            double yc = k1 * xc + b1;
            double yc2 = k2 * xc + b2;
            //求半径
            double x1 = linea.Start.X, y1 = linea.Start.Y;
            double m3 = (linea.End.Y - linea.Start.Y) / (linea.End.X - linea.Start.X);
            double b3 = 1.0;
            double c3 = -m3 * x1 + b3 * y1;
            radius = (Math.Abs(m3 * xc + c3 - yc)) / (Math.Sqrt(Math.Pow(m3, 2) + 1));
            center = new Vector2(xc, yc);
            return true;

        }
        private double GetParameterOfMidLine(Line2d linea, Line2d lineb, out double lineMidk1)
        {
            double x1 = linea.Start.X, x2 = linea.End.X, x3 = lineb.Start.X;
            double y1 = linea.Start.Y, y2 = linea.End.Y, y3 = lineb.Start.Y;
            double m1 = (linea.End.Y - linea.Start.Y) / (linea.End.X - linea.Start.X);
            double m2 = (lineb.End.Y - lineb.Start.Y) / (lineb.End.X - lineb.Start.X);
            double b1 = 1.0, b2 = 1.0;
            double c1 = -m1 * x1 + b1 * y1, c2 = -m2 * x3 + b2 * y3;
            //求延长线的交点
            //第一条线和第二条线的交点
            double xp1 = (c2 - c1) / (m1 - m2);
            double yp1 = m1 * xp1 + c1;

            //统一两条切线的方向 朝外
            double aStart = GetDistanceByTwoPoints(new(xp1, yp1), linea.Start);
            double aEnd = GetDistanceByTwoPoints(new(xp1, yp1), linea.End);
            if (aStart > aEnd)
            {
                linea = new Line2d(linea.End, linea.Start);
            }
            else
            {
                linea = linea;
            }
            double bStart = GetDistanceByTwoPoints(new(xp1, yp1), lineb.Start);
            double bEnd = GetDistanceByTwoPoints(new(xp1, yp1), lineb.End);
            if (bStart > bEnd)
            {
                lineb = new Line2d(lineb.End, lineb.Start);
            }
            else
            {
                lineb = lineb;
            }

            //求解两条延长线的夹角
            double angleDeg = GetDegreesByTwoLine(linea.Start, linea.End, lineb.Start, lineb.End);
            double angle1 = angleDeg / 2;

            ////统一过交点的参考线与两条切线的方向
            Line2d lineP = new Line2d();
            lineP.Start = new(xp1, yp1);
            lineP.End = new(xp1 + 100, yp1);

            //求交点与X轴的平行线 与 每条切线的夹角       
            double angleDeg1 = GetDegreesByTwoLine(linea.Start, linea.End, lineP.Start, lineP.End);
            double angleDeg2 = GetDegreesByTwoLine(lineb.Start, lineb.End, lineP.Start, lineP.End);
            if (IsTopInLine(linea.Start, linea.End, lineP.End) < 0)//点在线的左侧 
            {
                angleDeg1 = 360 - angleDeg1;
            }
            if (IsTopInLine(lineb.Start, lineb.End, lineP.End) < 0)
            {

                angleDeg2 = 360 - angleDeg2;
            }
            double lineMidDegree = 0;
            double comparey = 0;
            if (angleDeg1 < angleDeg2)
            {
                if ((angleDeg2 - angleDeg1) > 180)
                {
                    lineMidDegree = angleDeg2 + angle1;
                    if (lineMidDegree > 360)
                    {
                        lineMidDegree = lineMidDegree - 360;
                    }
                }
                else
                {
                    lineMidDegree = angleDeg1 + angle1;
                }
            }
            else
            {
                if ((angleDeg1 - angleDeg2) > 180)
                {
                    lineMidDegree = angleDeg1 + angle1;
                    if (lineMidDegree > 360)
                    {
                        lineMidDegree = lineMidDegree - 360;
                    }
                }
                else
                {
                    lineMidDegree = angleDeg2 + angle1;
                }
            }
            lineMidk1 = Math.Tan(lineMidDegree * Math.PI / 180);
            double lineMidb = yp1 - lineMidk1 * xp1;
            return lineMidb;
        }

        public override void CreateElement(LcElement element, Matrix3 matrix)
        {
            DocumentManager.CurrentRecorder.BeginAction("Circle");
            var circle = element as LcCircle;
            this.vportRt.ActiveElementSet.AddCircle(matrix.MultiplyPoint(circle.Center), circle.Radius);
            DocumentManager.CurrentRecorder.EndAction();
        }
        public override void CreateElement(LcElement element, Vector2 basePoint, double scaleFactor)
        {
            var circle = element as LcCircle;
            Matrix3 matrix3 = Matrix3.GetScale(scaleFactor, basePoint);
            this.vportRt.ActiveElementSet.AddCircle(matrix3.MultiplyPoint(circle.Center), circle.Radius * scaleFactor);
        }
        public override void CreateElement(LcElement element, Vector2 basePoint, Vector2 scaleVector)
        {
            var circle = element as LcCircle;
            Matrix3 matrix3 = Matrix3.GetScale(scaleVector, basePoint);
            this.vportRt.ActiveElementSet.AddCircle(matrix3.MultiplyPoint(circle.Center), circle.Radius * Vector2.Distance(basePoint, scaleVector));
        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var circle = element as LcCircle;
            var mcenter = matrix.MultiplyPoint(circle.Center);
            var medge = matrix.MultiplyPoint(circle.Center + new Vector2(0, circle.Radius));
            var mradius = Vector2.Distance(mcenter, medge);
            var center = this.vportRt.ConvertWcsToScr(mcenter).ToSKPoint();
            var radius = this.vportRt.ConvertWcsToScr(mradius);
            //get Layer color 
            bool isDragCopy = (matrix != Matrix3.Zero);
            var pen = this.GetDrawPen(circle);
            if (pen == Constants.defaultPen)
            {
                //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                {

                    canvas.DrawCircle(center, (float)radius, elePen);
                }
            }
            else
            {
                canvas.DrawCircle(center, (float)radius, pen);
            }

        }
        public override void Draw(SKCanvas canvas, LcElement element, Vector2 offset)
        {
            Matrix3 matrix = Matrix3.GetTranslate(offset);
            var circle = element as LcCircle;
            var mcenter = matrix.MultiplyPoint(circle.Center);
            var medge = matrix.MultiplyPoint(circle.Center + new Vector2(0, circle.Radius));
            var mradius = Vector2.Distance(mcenter, medge);
            var center = this.vportRt.ConvertWcsToScr(mcenter).ToSKPoint();
            var radius = this.vportRt.ConvertWcsToScr(mradius);
            //get Layer color 
            bool isDragCopy = (matrix != Matrix3.Zero);
            var pen = this.GetDrawPen(circle);
            if (pen == Constants.defaultPen)
            {
                //TODO:这里可以考虑将实线用颜色做KEY，对SKPaint进行缓存
                using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
                {

                    canvas.DrawCircle(center, (float)radius, elePen);
                }
            }
            else
            {
                canvas.DrawCircle(center, (float)radius, pen);
            }

        }

        public override void DrawAuxLines(SKCanvas canvas)
        {
            var mp = this.vportRt.PointerMovedPosition.ToVector2d();
            var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
            var auxPen = Constants.auxOrangeDashPen;

            if (_methodName == "CR")
            {
                if (cr_center == null) return;

                var movePoint = mp.ToSKPoint();
                var center = this.vportRt.ConvertWcsToScr(cr_center).ToSKPoint();

                if (center == movePoint) return;

                using (var pen = new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true })
                {
                    canvas.DrawLine(center, movePoint, auxPen);
                    var radius = (_methodArg == "D") ? SKPoint.Distance(center, movePoint) / 2 : SKPoint.Distance(center, movePoint);
                    canvas.DrawCircle(center, radius, pen);
                }
            }
            else if (_methodName == "2P")
            {
                if (_point1 == null) return;

                var movePoint = mp.ToSKPoint();
                var p1 = this.vportRt.ConvertWcsToScr(_point1).ToSKPoint();

                if (p1 == movePoint) return;

                using (var pen = new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true })
                {
                    canvas.DrawLine(p1, movePoint, auxPen);
                    var cx = (p1.X + movePoint.X) / 2;
                    var cy = (p1.Y + movePoint.Y) / 2;
                    var r = SKPoint.Distance(p1, movePoint) / 2;
                    canvas.DrawCircle(cx, cy, r, pen);
                }
            }
            else if (_methodName == "3P")
            {
                if (_point1 == null) return;
                var movePoint = mp.ToSKPoint();
                var p1 = this.vportRt.ConvertWcsToScr(_point1).ToSKPoint();
                //第二点
                if (_point2 == null)
                {
                    if (p1 == movePoint) return;
                    using (var pen = new SKPaint { Color = SKColors.Orange, IsStroke = true, PathEffect = Constants.SelectedEffect })
                    {
                        canvas.DrawLine(p1, movePoint, pen);

                    }
                }
                //第三点
                else
                {
                    var p2 = this.vportRt.ConvertWcsToScr(_point2).ToSKPoint();
                    if (p2 == movePoint) return;
                    using (var pen = new SKPaint { Color = SKColors.Orange, IsStroke = true, PathEffect = Constants.SelectedEffect })
                    {
                        canvas.DrawLine(p2, movePoint, pen);

                    }
                    using (var pen = new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true })
                    {
                        getCircleBy3P(p1.ToVector2d(), p2.ToVector2d(), movePoint.ToVector2d(), out var c, out var rd);
                        var cx = (float)c?.X; var cy = (float)c?.Y;
                        var r = (float)rd;
                        canvas.DrawCircle(cx, cy, r, pen);
                    }
                }
            }
            else if (_methodName == "CD")
            {
                if (cd_center == null) return;

                var movePoint = mp.ToSKPoint();
                var center = this.vportRt.ConvertWcsToScr(cd_center).ToSKPoint();

                if (center == movePoint) return;

                using (var pen = new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true })
                {
                    canvas.DrawLine(center, movePoint, auxPen);
                    var radius = SKPoint.Distance(center, movePoint) / 2;
                    canvas.DrawCircle(center, radius, pen);
                }
            }
            else if (_methodName == "T")
            {
                if (result  == true)
                {
                    var center1 = this.vportRt.ConvertWcsToScr(GetCircleByT1(wcs_mp)).ToSKPoint();//传入的圆心需为世界坐标
                    radius = GetDistanceByTwoParallelLine(li1[0], li1[1]);//实时渲染，因此需提前计算半径
                    var radius1 = this.vportRt.ConvertWcsToScr(radius);//转换为世界坐标
                    using (var pen = new SKPaint { Color = this.vportRt.GetAuxColorValue(), IsStroke = true })
                    {
                        canvas.DrawCircle(center1, (float)radius1, pen);
                    }
                }
                else
                {
                    if (_point3 == null)
                    {
                        return;
                    }
                    var movePoint = mp.ToSKPoint();
                    var p3 = this.vportRt.ConvertWcsToScr(_point3).ToSKPoint();
                    if (p3 == movePoint) return;
                    using (var pen = new SKPaint { Color = SKColors.Orange, IsStroke = true, PathEffect = Constants.SelectedEffect })
                    {
                        canvas.DrawLine(p3, movePoint, pen);
                    }
                }
            }

        }

        #region Grip
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var circle = element as LcCircle;
            var grips = new List<ControlGrip>();
            var gripCenter = new ControlGrip
            {
                Element = circle,
                Name = "Center",
                Position = circle.Center
            };
            grips.Add(gripCenter);

            var gripLeft = new ControlGrip
            {
                Element = circle,
                Name = "Left",
                Position = new Vector2(circle.Center.X - circle.Radius, circle.Center.Y)
            };
            grips.Add(gripLeft);

            var gripTop = new ControlGrip
            {
                Element = circle,
                Name = "Top",
                Position = new Vector2(circle.Center.X, circle.Center.Y + circle.Radius)
            };
            grips.Add(gripTop);

            var gripRight = new ControlGrip
            {
                Element = circle,
                Name = "Right",
                Position = new Vector2(circle.Center.X + circle.Radius, circle.Center.Y)
            };
            grips.Add(gripRight);

            var gripBottom = new ControlGrip
            {
                Element = circle,
                Name = "Bottom",
                Position = new Vector2(circle.Center.X, circle.Center.Y - circle.Radius)
            };
            grips.Add(gripBottom);
            return grips.ToArray();
        }
        private string _gripName;
        private Vector2 _position;
        private LcCircle _circle;

        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var circle = element as LcCircle;
            _circle = circle;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                Vector2 dragposition = position;
                if(this.vportRt.SnapRt?.Current != null)
                {
                    dragposition = this.vportRt.SnapRt.Current.SnapPoint;
                }
                if (gripName == "Center")
                    circle.Set(center: dragposition);
                else
                {
                    var r = Vector2.Distance(circle.Center, dragposition);
                    circle.Set(radius: r);
                }
            }
        }

        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_circle == null) return;

            var center = this.vportRt.ConvertWcsToScr(_circle.Center);
            var r = this.vportRt.ConvertWcsToScr(_circle.Radius);
            if (_gripName == "Center")
                center = this.vportRt.ConvertWcsToScr(_position);
            else
            {
                var wr = Vector2.Distance(_circle.Center, _position);
                r = this.vportRt.ConvertWcsToScr(wr);
            }
            canvas.DrawCircle(center.ToSKPoint(), (float)r, Constants.draggingPen);
        }

        #endregion

        public override List<PropertyObserver> GetPropertyObservers()
        {
            return new List<PropertyObserver>()
            {
                new PropertyObserver()
                {
                    Name = "CenterX",
                    DisplayName = "圆心 X 坐标",
                    Getter = (ele) => Math.Round((ele as LcCircle).Center.X, 4),  
                    Setter = (ele, value) =>
                    {
                        var circle = (ele as LcCircle);
                        var x = Convert.ToDouble(value);
                        var cen = new Vector2(x, circle.Center.Y);
                        circle.Set(center : cen);
                    }
                },
                new PropertyObserver()
                {
                    Name = "CenterY",
                    DisplayName = "圆心 Y 坐标",
                    Getter = (ele) => Math.Round((ele as LcCircle).Center.Y, 4),
                    Setter = (ele, value) =>
                    {
                        var circle = (ele as LcCircle);
                        var y = Convert.ToDouble(value);
                        var cen = new Vector2(circle.Center.X, y);
                        circle.Set(center : cen);
                    }
                },
                new PropertyObserver()
                {
                    Name = "Radius",
                    DisplayName = "半径",
                    Getter = (ele) => Math.Round((ele as LcCircle).Radius, 4),
                    Setter = (ele, value) =>
                    {
                        var circle = (ele as LcCircle);
                        var radius = Convert.ToDouble(value);
                        circle.Set(radius : radius);
                    }
                },
                new PropertyObserver()
                {
                    Name = "Diameter",
                    DisplayName = "直径",
                    Getter = (ele) => Math.Round((ele as LcCircle).Radius * 2, 4),
                    Setter = (ele, value) =>
                    {
                        var circle = (ele as LcCircle);
                        var radius = Convert.ToDouble(value) / 2;
                        circle.Set(radius : radius);
                    }
                },
                new PropertyObserver()
                {
                    Name = "Circumference",
                    DisplayName = "周长",
                    Getter = (ele) => Math.Round((ele as LcCircle).Radius * 2 * Math.PI, 4),
                    Setter = (ele, value) =>
                    {
                        var circle = (ele as LcCircle);
                        var radius = Convert.ToDouble(value) / 2 / Math.PI;
                        circle.Set(radius : radius);
                    }
                },
                new PropertyObserver()
                {
                    Name = "Area",
                    DisplayName = "面积",
                    Getter = (ele) =>
                    {
                        var radius = (ele as LcCircle).Radius;
                        return Math.Round(Math.Pow(radius, 2) * Math.PI, 4);
                    },
                    Setter = (ele, value) =>
                    {
                        var circle = (ele as LcCircle);
                        var area = Convert.ToDouble(value);
                        var radius = Math.Sqrt(area / Math.PI);
                        circle.Set(radius : radius);
                    }
                },
                new PropertyObserver()
                {
                    Name = "NormalX",
                    DisplayName = "法向 X 坐标",
                    Getter = (ele) => 0
                },
                new PropertyObserver()
                {
                    Name = "NormalY",
                    DisplayName = "法向 Y 坐标",
                    Getter = (ele) => 0
                },
                new PropertyObserver()
                {
                    Name = "NormalZ",
                    DisplayName = "法向 Z 坐标",
                    Getter = (ele) => 1
                },
            };
        }
        /// <summary>
        /// 判断直线和圆的交点
        /// </summary>
        public bool GetIntersectionCircle(double startx, double starty, double endx, double endy, double centerx, double centery, double Radius, ref double[] ptInter1, ref double[] ptInter2)
        {
            double EPS = 0.01;  //误差允许范围
            double Radius2 = Radius * Radius;

            ptInter1[0] = ptInter2[0] = 65536.0;
            ptInter2[1] = ptInter2[1] = 65536.0;

            //求线段的长度
            double fDis = Math.Sqrt((endx - startx) * (endx - startx) + (endy - starty) * (endy - starty));
            double[] d = new double[2];
            d[0] = (endx - startx) / fDis;
            d[1] = (endy - starty) / fDis;
            double[] E = new double[2];
            E[0] = centerx - startx;
            E[1] = centery - starty;
            double a = E[0] * d[0] + E[1] * d[1];
            double a2 = a * a;
            double e2 = E[0] * E[0] + E[1] * E[1];
            if ((Radius2 - e2 + a2) < 0)
            {
                return false;
            }
            else
            {
                double f = System.Math.Sqrt(Radius2 - e2 + a2);
                double t = a - f;
                if (((t - 0.0) > -EPS) && (t - fDis) < EPS)
                {
                    ptInter1[0] = Math.Round(startx + t * d[0], 2);
                    ptInter1[1] = Math.Round(starty + t * d[1], 2);
                }
                t = a + f;
                if (((t - 0.0) > -EPS) && (t - fDis) < EPS)
                {
                    ptInter2[0] = Math.Round(startx + t * d[0], 2);
                    ptInter2[1] = Math.Round(starty + t * d[1], 2);
                }
                return true;
            }
        }

        public override SnapPointResult SnapPoint(SnapRuntime snapRt, LcElement element, Vector2 point, bool forRef, Vector2 PrePoint = null)
        {

            var maxDistance = vportRt.GetSnapMaxDistance();
            LcCircle cir = element as LcCircle;
            var sscur = SnapSettings.Current;
            var result = new SnapPointResult { Element = element };
            var icir = cir.GetCurves()[0];

            if (SnapSettings.Current.ObjectOn)
            {

                if (sscur.PointType.Has(SnapPointType.Center))
                {
                    if ((point - cir.Center).Length() <= maxDistance)
                    {
                        result.Point = cir.Center;
                        result.Name = "Center";

                        result.Curves.Add(new SnapRefCurve(SnapPointType.Center, icir));
                    }
                }

                if (sscur.PointType.Has(SnapPointType.Quadrant))
                {
                    foreach (var item in GetControlGrips(element))
                    {
                        if (item.Name != "Center")
                        {
                            if ((point - item.Position).Length() <= maxDistance)
                            {
                                result.Point = item.Position;
                                result.Name = item.Name;
                                result.Curves.Add(new SnapRefCurve(SnapPointType.Quadrant, icir));
                            }
                        }
                    }
                }
                if (!forRef && result.Point == null)
                {
                    var distance = Vector2.Distance(point, cir.Center);
                    if (sscur.PointType.Has(SnapPointType.Nearest))
                    {

                        if (Math.Abs(cir.Radius - distance) < maxDistance)
                        {
                            double[] x = new double[2];
                            double[] y = new double[2];
                            //bool jp = GetIntersectionCircle(point.X, point.Y, cir.Center.X, cir.Center.Y, cir.Center.X, cir.Center.Y, cir.Radius, ref x, ref y);

                            var distancex = Vector2.Distance(point, new Vector2(x[0], x[1]));
                            var distancey = Vector2.Distance(point, new Vector2(y[0], y[1]));


                            var dir = (point - cir.Center).Normalize();

                            var nearest = cir.Center + dir * cir.Radius;

                            //    docRt.CommandCtrl.WriteInfo(x[0].ToString() + "," + x[1].ToString() + "   " + y[0].ToString() + "," + y[1].ToString()+"  "+ nearest.X.ToString() + "," + nearest.Y.ToString());
                            //if (distancex < distancey)
                            //    nearest = new Vector2d(x[0], x[1]);
                            //else
                            //    nearest = new Vector2d(y[0], y[1]);
                            result.Point = nearest;
                            result.Name = "Nearest";
                            result.Curves.Add(new SnapRefCurve(SnapPointType.Nearest, icir));
                        }
                    }

                }

            }

            if (result.Point != null)
                return result;
            else
                return null;
        }
    }
}
